#pragma once
#include "net.hpp"
#include "message.hpp"

namespace bitrpc {
    class Callback {
        public:
            using ptr = std::shared_ptr<Callback>;
            virtual void onMessage(const BaseConnection::ptr &conn, BaseMessage::ptr &msg) = 0;
    };

    template<typename T>
    class CallbackT : public Callback{
        public:
            using ptr = std::shared_ptr<CallbackT<T>>;
            using MessageCallback = std::function<void(const BaseConnection::ptr &conn, std::shared_ptr<T> &msg)>;
            CallbackT(const MessageCallback &handler):_handler(handler) { }
            void onMessage(const BaseConnection::ptr &conn, BaseMessage::ptr &msg) override {
                auto type_msg = std::dynamic_pointer_cast<T>(msg);
                _handler(conn, type_msg);
            }
        private:
            MessageCallback _handler; /* 注意callbackT内部保存的_handler的类型不是T，而是MessageCallback */
    };
    class Dispatcher {
        public:
            using ptr = std::shared_ptr<Dispatcher>;
            template<typename T>              /* 回调函数的类型是CallbackT<T>::MessageCallback */
            void registerHandler(MType mtype, const typename CallbackT<T>::MessageCallback &handler) {
                std::unique_lock<std::mutex> lock(_mutex);
                auto cb = std::make_shared<CallbackT<T>>(handler);/* 创建一个CallbackT<T>类型来存储handler，传进来的回调函数 */
                _handlers.insert(std::make_pair(mtype, cb));
            }
            void onMessage(const BaseConnection::ptr &conn, BaseMessage::ptr &msg) {/* 这里的msg肯定是BaseMessage类型，是在用户创建接口时指定类型 */
                //找到消息类型对应的业务处理函数，进行调用即可
                std::unique_lock<std::mutex> lock(_mutex);
                auto it = _handlers.find(msg->mtype());  /* 根据msg选择执行的handler */
                if (it != _handlers.end()) {
                    return it->second->onMessage(conn, msg);
                }
                //没有找到指定类型的处理回调--因为客户端和服务端都是我们自己设计的，因此不可能出现这种情况
                ELOG("收到未知类型的消息: %d！", msg->mtype());
                conn->shutdown();
            }
        private:
            std::mutex _mutex;
            std::unordered_map<MType, Callback::ptr> _handlers;/*  用父类指针来指向CallbackT<T> */
    };
}

/*
     方便用户注册函数,用户注册一个指定类型的回调函数，我们进行封装
     1.有Dispatcher template<typename T>的原因是，想要对于用户进行注册的时候可以注册onmessage的第二个参数
     不为BaseMessage* ptr而为对应的功能模块的指针，这样可以更方便调用每个功能模块的功能(虽然可以在函数内部强转，但是增加用户使用难度)    
     2.std::unordered_map<MType, Callback::ptr> _handlers只能存储一个类型的变量，所以创建class callbackT和callback;
     3.回调函数的类型是CallbackT<T>::MessageCallback，Dispatcher的类型是T 
*/